package com.uam.core.entity.uitls;

/**
 * 
 * @author lishf
 */
public class SpatialUtil {

	public static boolean pointIsValid(double lon, double lat) {
		return lon >= -180.00D && lon <= 180.00D && lat >= -90.00D && lat <= 90.00D;
	}

	/**
	 * 求两个将经纬度的直线距离,单位M
	 * 
	 * @param startLon 开始点经度
	 * @param startLat 开始点纬度
	 * @param endLon   结束点经度
	 * @param endLat   结束点纬度
	 * @return
	 */
	public static double computeDistance(double startLon, double startLat, double endLon, double endLat) {
		double tempStartLat = startLat * Math.PI / 180.00D;
		double tempEndLat = endLat * Math.PI / 180.00D;
		return Math.round(2.00D
				* Math.asin(Math.sqrt(Math.pow(Math.sin((tempStartLat - tempEndLat) / 2.00D), 2.00D)
						+ Math.cos(tempStartLat) * Math.cos(tempEndLat) * Math.pow(
								Math.sin((startLon * Math.PI / 180.00D - endLon * Math.PI / 180.00D) / 2.00D), 2.00D)))
				* 6378137.00D * 10000.00D) / 10000.00D;
	}

    public static String computeDirection(double centreLon, double centreLat, double lon, double lat, double distance) {
    	return SpatialUtil.computeDirection(centreLon, centreLat, lon, centreLat, distance, 50.00D, 0.30D);
    }

    public static String computeDirection(double centreLon, double centreLat, double lon, double lat, double distance, double startDistance, double startAngleRatio) {
        StringBuilder direction = new StringBuilder();
        if (distance > startDistance) {
        	double latDifference = centreLat - lat;
            double latDistance = latDifference * 111000.00D; // 南北位移
            double lonDistance = (centreLon - lon) * 111000.00D * Math.abs(Math.cos(0.0174533D * (Math.abs(latDifference) / 2.00D))); // 东西位移
            if (Math.abs(lonDistance / distance) > startAngleRatio) {
                if (lonDistance > 0.00D) {
                    direction.append('西');
                } else {
                    direction.append('东');
                }
            }
            if (Math.abs(latDistance / distance) > startAngleRatio) {
                if (latDistance > 0.00D) {
                    direction.append('南');
                } else {
                    direction.append('北');
                }
            }
        }
        return direction.toString();
    }

	public static double computeCosine(double lastLon, double lastLat, double currLon, double currLat, double nextLon,
			double nextLat) {
		double lastDistance = SpatialUtil.computeDistance(lastLon, lastLat, currLon, currLat);
		double nextDistance = SpatialUtil.computeDistance(currLon, currLat, nextLon, nextLat);
		return Math.abs((Math.pow(lastDistance, 2.00D) + Math.pow(nextDistance, 2.00D)
				- Math.pow(SpatialUtil.computeDistance(lastLon, lastLat, nextLon, nextLat), 2.00D))
				/ (2.00D * lastDistance * nextDistance));
	}

	public static double computeCosine(double startLon, double startLat, double currLon, double currLat, double endLon,
			double endLat, double lineDistance) {
		double startDistance = SpatialUtil.computeDistance(startLon, startLat, currLon, currLat);
		return (Math.pow(startDistance, 2.00D) + Math.pow(lineDistance, 2.00D)
				- Math.pow(SpatialUtil.computeDistance(currLon, currLat, endLon, endLat), 2.00D))
				/ (2.00D * startDistance * lineDistance);
	}
	
	public static double[] computePerpendicular(double[] point, double[][] line) {
	    double[] perpendicular = new double[2];
	    double[] start = line[0];
	    double[] end = line[line.length - 1];
	    double denominator = end[0] - start[0];
	    double numerator = end[1] - start[1];
	    if (denominator == 0.00D) {
			perpendicular[0] = end[0];
			perpendicular[1] = point[1];
		} else if (numerator == 0.00D) {
			perpendicular[0] = point[0];
			perpendicular[1] = end[1];
		} else {
			double slope = numerator / denominator;
			double squareSlope = Math.pow(slope, 2.00D);
			perpendicular[0] = ((squareSlope * start[0] + slope * point[1] - slope * start[1]
					+ point[0]) / (squareSlope + 1.00D));
			perpendicular[1] = ((slope * point[0] - slope * start[0] + squareSlope * point[1]
					+ start[1]) / (squareSlope + 1.00D));
		}
	    return perpendicular;
	}
	
	public static double normalizeLon(double lon) {
		if (lon >= 0.00D) {
			if (lon > 360.00D) {
				lon = lon % 360.00D;
			}
			if (lon > 180.00D) {
				lon = (lon % 180.00D) - 180.00D;
			}
		} else {
			if (lon < -360.00D) {
				lon = lon % 360.00D;
			}
			if (lon < -180.00D) {
				lon = (lon % 180.00D) + 180.00D;
			}
		}
		return lon;
	}
	
	public static double normalizeLat(double lat) {
		if (lat >= 0.00D) {
			if (lat > 360.00D) {
				lat = lat % 360.00D;
			}
			if (lat > 270.00D) {
				lat = -90.00D + (lat % 90.00D);
			} else if (lat > 180.00D) {
				lat = -(lat % 180.00D);
			} else if (lat > 90.00D) {
				lat = 90.00D - (lat % 90.00D);
			}
		} else {
			if (lat < -360.00D) {
				lat = lat % 360.00D;
			}
			if (lat < -270.00D) {
				lat = 90.00D + (lat % 90.00D);
			} else if (lat < -180.00D) {
				lat = -(lat % 180.00D);
			} else if (lat < -90.00D) {
				lat = -90.00D - (lat % 90.00D);
			}
		}
		return lat;
	}
	
	public static double[] normalizeLonLat(double lon, double lat) {
		return new double[] { SpatialUtil.normalizeLon(lon), SpatialUtil.normalizeLat(lat) };
	}

}
